﻿using System;
using DrawTools;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
using System.Linq;

namespace ShapeManager
{
    using PointList = List<PointF>;
    using PointEnumerator = IEnumerator<PointF>;
    internal class UPolygon : ULine
    {
        private PointList pointArray;         //点集
        private Cursor HandleCursor {  get; set; } 
        private const string entryLength = "Length";
        private const string entryPoint = "Point";
        public override int HandleCount => pointArray.Count;
        public UPolygon() : base()
        {
            pointArray = new PointList();
            Type = ShapeType.Polygon;
            Description = "多边形";
            Initialize();
        }
        public UPolygon(int x1, int y1, int x2, int y2) : base()
        {
            try
            {
                HandleCursor = new Cursor("cursor/PolyHandles.cur");
            }
            catch (Exception)
            {
                HandleCursor = Cursors.SizeAll;
            }
            pointArray = new PointList();
            Type = ShapeType.Polygon;
            Description = "多边形";
            pointArray.Add(new Point(x1, y1));
            pointArray.Add(new Point(x2, y2));
            Initialize();
        }
        public override DrawObject Clone()
        {
            UPolygon uPolygon = new UPolygon();
            uPolygon.ID = this.ID;
            foreach (PointF p in this.pointArray)
                uPolygon.pointArray.Add(p);
            Clone(uPolygon);
            return uPolygon;
        }
        public override void Draw(Graphics graphics)
        {
            float x1 = 0;
            float y1 = 0;     // 前一点
            float x2;
            float y2;         // 当前点
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            using (Pen pen = new Pen(BorderColor, BorderWidth))
            {
                PointEnumerator enumerator = pointArray.GetEnumerator();
                if (enumerator.MoveNext())
                {
                    x1 = enumerator.Current.X;
                    y1 = enumerator.Current.Y;
                }
                while (enumerator.MoveNext())
                {
                    x2 = enumerator.Current.X;
                    y2 = enumerator.Current.Y;
                    graphics.DrawLine(pen, x1, y1, x2, y2);
                    x1 = x2;
                    y1 = y2;
                }
            }
            DrawCenter(graphics);
            DrawDescription(graphics);
        }
        public void AddPoint(Point point)
        {
            pointArray.Add(point);
        }
        /// <summary> 获取指定手柄 </summary>
        public override PointF GetHandle(int handleNumber)
        {
            if (handleNumber < 1) handleNumber = 1;
            if (handleNumber > pointArray.Count) handleNumber = pointArray.Count;
            return pointArray[handleNumber - 1];
        }
        public override Cursor GetHandleCursor(int handleNumber)
        {
            if(HandleCursor == null)
            {
                return Cursors.Default;
            }
            else
            {
                return HandleCursor;
            }
        }
        public override void MoveHandleTo(PointF point, int handleNumber)
        {
            if (handleNumber < 1)
                handleNumber = 1;
            if (handleNumber > pointArray.Count)
                handleNumber = pointArray.Count;
            pointArray[handleNumber - 1] = point;
            Invalidate();
        }
        public override void Move(float deltaX, float deltaY)
        {
            int n = pointArray.Count;
            for (int i = 0; i < n; i++)
                pointArray[i] = new PointF(pointArray[i].X + deltaX, pointArray[i].Y + deltaY);
            Invalidate();
        }
        public override void SaveToStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            info.AddValue($"{entryLength}{orderNumber}", pointArray.Count);
            int i = 0;
            foreach (PointF p in pointArray)
                info.AddValue($"{entryLength}{orderNumber}{i++}", p);
            base.SaveToStream(info, orderNumber); 
        }
        public override void LoadFromStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            PointF point;
            int n = info.GetInt32($"{entryLength}{orderNumber}");
            for (int i = 0; i < n; i++)
            {
                point = (Point)info.GetValue($"{entryLength}{orderNumber}{i++}",typeof(Point));
                pointArray.Add(point);
            }
            base.LoadFromStream(info, orderNumber);
        }
        /// <summary> 创建用于命中检测的图形对象 </summary>
        protected override void CreateObjects()
        {
            if (AreaPath != null)
                return;
            // 创建包含所有多边形顶点的封闭路径
            AreaPath = new GraphicsPath();
            float x1 = 0, y1 = 0;     // 上一点
            float x2, y2;             // 当前点
            PointEnumerator enumerator = pointArray.GetEnumerator();
            if (enumerator.MoveNext())
            {
                x1 = enumerator.Current.X;
                y1 = enumerator.Current.Y;
            }
            while (enumerator.MoveNext())
            {
                x2 = enumerator.Current.X;
                y2 = enumerator.Current.Y;
                AreaPath.AddLine(x1, y1, x2, y2);
                x1 = x2;
                y1 = y2;
            }
            AreaPath.CloseFigure();
            // 根据路径创建区域
            AreaRegion = new Region(AreaPath);
        }
        public override void DrawCenter(Graphics graphics)
        {
            RectangleF rectangle = Region;
            // 1、计算矩形中心坐标
            PointF center = CalculateCenter(pointArray);
            // 2、线长度大小（根据矩形大小自适应）
            float lineHalfLength = 3;
            // 3、绘制箭头
            using (Pen arrowPen = new Pen(BackColor, BorderWidth))
            {
                // 3.1 水平线
                PointF left = new PointF(center.X - lineHalfLength, center.Y);
                PointF right = new PointF(center.X + lineHalfLength, center.Y);
                graphics.DrawLine(arrowPen, left, right);
                // 3.2 垂直线
                PointF top = new PointF(center.X, center.Y - lineHalfLength);
                PointF bottom = new PointF(center.X, center.Y + lineHalfLength);
                graphics.DrawLine(arrowPen, top, bottom);
            }
        }
        protected void DrawDescription(Graphics graphics)
        {
            using (SolidBrush brush = new SolidBrush(Color.LightGreen))
            {
                Font descriptionFont = new Font("Arial", 9);
                string text = $"{Description}_{ID}(X:{X},Y:{Y})";
                SizeF maxTextSize = graphics.MeasureString(text, descriptionFont);
                PointF center = CalculateCenter(pointArray);
                float x = center.X - maxTextSize.Width / 2;
                float y = center.Y - maxTextSize.Height;
                graphics.DrawString(text, descriptionFont, brush, x, y);
            }
        }
        public PointF CalculateCenter(IEnumerable<PointF> points)
        {
            if (points == null || !points.Any())
                throw new ArgumentException("点集不能为空");
            float minX = float.MaxValue, maxX = float.MinValue;
            float minY = float.MaxValue, maxY = float.MinValue;
            foreach (var point in points)
            {
                minX = Math.Min(minX, point.X);
                maxX = Math.Max(maxX, point.X);
                minY = Math.Min(minY, point.Y);
                maxY = Math.Max(maxY, point.Y);
            }
            return new PointF((minX + maxX) / 2, (minY + maxY) / 2);
        }
    }
}
